﻿/// <summary>
// CodeFx.MySqlProviders - .NET Providers for MySql using the framework CodeFx
// Laurent Morisseau
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Laurent Morisseau
/// </summary>
/// <author><a href="mailto:laurent.morisseau@gmail.com">Laurent Morisseau</a></author>


   using System;
   using System.Web;
   using System.Web.Profile;
   using System.Globalization;
   using System.ComponentModel;
   using System.Collections;
   using System.Collections.Specialized;
   using System.Data;
   using System.IO;
   using System.Text;
   using System.Configuration.Provider;
   using System.Configuration;
   using MySql.Data.MySqlClient;
   using CodeFx;
   using System.Collections.Generic;

namespace CodeFx.MySqlProviders
{
    public sealed class MySQLProfileProvider : ProfileProvider {

        // Fields
        private string _AppName;
        private string _sqlConnectionString;

        public override void Initialize(string name, NameValueCollection config) {
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            if ((name == null) || (name.Length < 1))
            {
                name = "MySqlProfileProvider";
            }
            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "ProfileSqlProvider_description");
            }
            base.Initialize(name, config);
            string text1 = config["connectionStringName"];
            if ((text1 == null) || (text1.Length < 1))
            {
                throw new ProviderException("Connection_name_not_specified");
            }

            /// ConnectionString
            ConnectionString.Current.ConnectionStringName = config["connectionStringName"];
            
            this._AppName = config["applicationName"];
            if (string.IsNullOrEmpty(this._AppName))
            {
                throw new ProviderException("Provider_application_name_not_null");
            }
            if (this._AppName.Length > 0x100)
            {
                throw new ProviderException("Provider_application_name_too_long");
            }
            config.Remove("commandTimeout");
            config.Remove("connectionStringName");
            config.Remove("applicationName");
            if (config.Count > 0)
            {
                string text2 = config.GetKey(0);
                if (!string.IsNullOrEmpty(text2))
                {
                    throw new ProviderException("Provider_unrecognized_attribute");
                }
            }

        }

        public override string ApplicationName {
            get
            {
                return this._AppName;
            }
            set
            {
                if (value.Length > 0x100)
                {
                    throw new ProviderException("Provider_application_name_too_long");
                }
                this._AppName = value;
            }
        }

        public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext sc, SettingsPropertyCollection properties) {
            SettingsPropertyValueCollection collection1 = new SettingsPropertyValueCollection();
            if (properties.Count >= 1)
            {
                string text1 = (string)sc["UserName"];
                foreach (SettingsProperty property1 in properties)
                {
                    if (property1.SerializeAs == SettingsSerializeAs.ProviderSpecific)
                    {
                        if (property1.PropertyType.IsPrimitive || (property1.PropertyType == typeof(string)))
                        {
                            property1.SerializeAs = SettingsSerializeAs.String;
                        }
                        else
                        {
                            property1.SerializeAs = SettingsSerializeAs.Xml;
                        }
                    }
                    collection1.Add(new SettingsPropertyValue(property1));
                }
                if (!string.IsNullOrEmpty(text1))
                {
                    this.GetPropertyValuesFromDatabase(text1, collection1);
                }
            }
            return collection1;


        }

        private void GetPropertyValuesFromDatabase(string userName, SettingsPropertyValueCollection svc)
        {

            HttpContext context1 = HttpContext.Current;
            string[] textArray1 = null;
            string text1 = null;
            byte[] buffer1 = null;
            try
            {
                uint appId = ApplicationId;
                if (appId == 0)
                    return;
                Aspnet_usersDAL user = Aspnet_usersDTO.SelectByFk_ApplicationId_UserNameWithPersistance(appId, userName);
                if (user == null)
                    return;
                Aspnet_usersDTO.Update_LastActivityDateWithPersistance(user.UserId, userName  );
                List<Aspnet_profileDAL> profiles = Aspnet_profileDTO.SelectByFk_UserId(user.UserId);

                if ((profiles!=null) && (profiles.Count >0))
                {
                    Aspnet_profileDAL profile = profiles[0] as Aspnet_profileDAL;
                    textArray1 = profile.PropertyNames.Split(new char[] { ':' });
                    text1 = profile.propertyValuesString;
                    /// A voir 
                    buffer1 = profile.PropertyValuesBinary;
                   if (buffer1 == null)
                  {
                        buffer1 = new byte[0];
                  }
                }
                ParseDataFromDB(textArray1, text1, buffer1, svc);
            }
            catch
            {
                throw;
            }

        }
        internal static void PrepareDataForSaving(ref string allNames, ref string allValues, ref byte[] buf, bool binarySupported, SettingsPropertyValueCollection properties, bool userIsAuthenticated)
        {
            StringBuilder builder1 = new StringBuilder();
            StringBuilder builder2 = new StringBuilder();
            MemoryStream stream1 = binarySupported ? new MemoryStream() : null;
            try
            {
                try
                {
                    bool flag1 = false;
                    foreach (SettingsPropertyValue value1 in properties)
                    {
                        if (value1.IsDirty && (userIsAuthenticated || ((bool)value1.Property.Attributes["AllowAnonymous"])))
                        {
                            flag1 = true;
                            break;
                        }
                    }
                    if (!flag1)
                    {
                        return;
                    }
                    foreach (SettingsPropertyValue value2 in properties)
                    {
                        if ((userIsAuthenticated || ((bool)value2.Property.Attributes["AllowAnonymous"])) && (value2.IsDirty || !value2.UsingDefaultValue))
                        {
                            int num1 = 0;
                            int num2 = 0;
                            string text1 = null;
                            if (value2.Deserialized && (value2.PropertyValue == null))
                            {
                                num1 = -1;
                            }
                            else
                            {
                                /// Pb MEDIUM TRUST
                                //object obj1 = value2.SerializedValue;
                                object obj1 = value2.PropertyValue ;
                                /// end
                                if (obj1 == null)
                                {
                                    num1 = -1;
                                }
                                else
                                {
                                    text1 = obj1.ToString();
                                    num1 = text1.Length;
                                    num2 = builder2.Length;
                                    
                                }
                            }
                            builder1.Append(value2.Name + ":" + ((text1 != null) ? "S" : "S") + ":" + num2.ToString(CultureInfo.InvariantCulture) + ":" + num1.ToString(CultureInfo.InvariantCulture) + ":");
                            if (text1 != null)
                            {
                                builder2.Append(text1);
                            }
                        }
                    }
                    
                    if (binarySupported)
                    {
                        buf = stream1.ToArray();
                    }
                }
                finally
                {
                    if (stream1 != null)
                    {
                        stream1.Close();
                    }
                }
            }
            catch
            {
                throw;
            }
            allNames = builder1.ToString();
            allValues = builder2.ToString();
        }


        internal static void ParseDataFromDB(string[] names, string values, byte[] buf, SettingsPropertyValueCollection properties)
        {
            if (((names != null) && (values != null)) && ((buf != null) && (properties != null)))
            {
                    for (int num1 = 0; num1 < (names.Length / 4); num1++)
                    {
                        string text1 = names[num1 * 4];
                        SettingsPropertyValue value1 = properties[text1];
                        if (value1 != null)
                        {
                            int num2 = int.Parse(names[(num1 * 4) + 2], CultureInfo.InvariantCulture);
                            int num3 = int.Parse(names[(num1 * 4) + 3], CultureInfo.InvariantCulture);
                            if ((num3 == -1) && !value1.Property.PropertyType.IsValueType)
                            {
                                value1.PropertyValue = null;
                                value1.IsDirty = false;
                                value1.Deserialized = true;
                            }
                            /// Pb MEDIUM TRUST  
                            if (((names[(num1 * 4) + 1] == "S") && (num2 >= 0)) && ((num3 > 0) && (values.Length >= (num2 + num3))))
                            {
                                //value1.SerializedValue = values.Substring(num2, num3);
                                value1.PropertyValue  = values.Substring(num2, num3);
                            }
                            //if (((names[(num1 * 4) + 1] == "B") && (num2 >= 0)) && ((num3 > 0) && (buf.Length >= (num2 + num3))))
                            //{
                            //    byte[] buffer1 = new byte[num3];
                            //    Buffer.BlockCopy(buf, num2, buffer1, 0, num3);
                            //    value1.SerializedValue = buffer1;
                            //}
                            /// end
                        }
                    }
            }
        }
        public override void SetPropertyValues(SettingsContext sc, SettingsPropertyValueCollection properties) {

            string text1 = (string)sc["UserName"];
            bool flag1 = (bool)sc["IsAuthenticated"];
            if (((text1 != null) && (text1.Length >= 1)) && (properties.Count >= 1))
            {
                string text2 = string.Empty;
                string text3 = string.Empty;
                byte[] buffer1 = null;
                PrepareDataForSaving(ref text2, ref text3, ref buffer1, true, properties, flag1);
                if (text2.Length != 0)
                {
                        uint appid = ApplicationId;
                        if (appid == 0)
                        {
                            Aspnet_applicationsDAL newApp = new Aspnet_applicationsDAL();
                            newApp.ApplicationName = this.ApplicationName;
                            Aspnet_applicationsDTO.Insert(newApp);
                            appid = Aspnet_applicationsDTO.GetLastId(this.ApplicationName);
                        }
                        Aspnet_usersDAL user = Aspnet_usersDTO.SelectByFk_ApplicationId_UserNameWithPersistance(appid, text1);
                        uint userid = 0;
                        if (user != null)
                        {
                            userid = user.UserId;
                            Aspnet_usersDTO.Update_LastActivityDateWithPersistance(user.UserId, text1);
                        }
                        else
                        {
                            user = new Aspnet_usersDAL();
                            user.UserName = text1;
                            user.ApplicationId = appid;
                            user.IsAnonymous = ConvertHelper.BoolToByte(!flag1);
                            user.LastActivityDate = DateTime.UtcNow;
                            Aspnet_usersDTO.Insert(user);
                            userid = Aspnet_usersDTO.GetLastId(user);
                        }
                        Aspnet_profileDAL profile = new Aspnet_profileDAL();
                        profile.UserId = userid;
                        profile.PropertyNames = text2;
                        profile.propertyValuesString = text3;
                        profile.PropertyValuesBinary = buffer1;
                        profile.LastUpdatedDate = DateTime.UtcNow;
                        if (Aspnet_profileDTO.Exist(userid))
                            Aspnet_profileDTO.Update(profile);
                        else
                            Aspnet_profileDTO.Insert(profile);
                }
            }

        }

        public override int DeleteProfiles(ProfileInfoCollection profiles)
        {

            if (profiles == null)
            {
                throw new ArgumentNullException("profiles");
            }

            if (profiles.Count < 1)
            {
                throw new ArgumentException("Profiles collection is empty", "profiles");
            }

            try
            {

                int numDeleted = 0;
                uint appId = ApplicationId;
                foreach (ProfileInfo profile in profiles)
                    if (DeleteProfile(profile.UserName.Trim(), appId))
                        numDeleted++;
                return numDeleted;
            }
            catch
            {
                throw;
            }

        }

        public override int DeleteProfiles(string[] usernames) {
            try {

                int numDeleted = 0;
                    uint appId = ApplicationId;
                    foreach (string username in usernames)
                        if (DeleteProfile(username, appId))
                            numDeleted++;
                return numDeleted;
            }
            catch {
                throw;
            }
        }

        public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
        {

            object obj1 = Aspnet_profileDTO.Delete_InactiveProfiles(ApplicationId, (int)authenticationOption, userInactiveSinceDate.ToUniversalTime());
            if (obj1 == null)
            {
                return 0;
            }
            return (int)obj1;
            
        }

        public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
        {
            object obj1 = Aspnet_profileDTO.Count_InactiveProfiles(ApplicationId, (int)authenticationOption, userInactiveSinceDate.ToUniversalTime());
            if (obj1 == null)
            {
                return 0;
            }
            return (int)obj1;
        }

        public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords)
        {
            return this.GetProfilesForQuery(new MySqlParameter[0], authenticationOption, pageIndex, pageSize, out totalRecords);

        }

        public override ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            MySqlParameter[] parameterArray1 = new MySqlParameter[] { this.CreateInputParam("?InactiveSinceDate", MySqlDbType.Datetime, userInactiveSinceDate.ToUniversalTime()) };
            return this.GetProfilesForQuery(parameterArray1, authenticationOption, pageIndex, pageSize, out totalRecords);

        }

        public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            MySqlParameter[] parameterArray1 = new MySqlParameter[] { this.CreateInputParam("?UserNameToMatch", MySqlDbType.VarChar, usernameToMatch) };
            return this.GetProfilesForQuery(parameterArray1, authenticationOption, pageIndex, pageSize, out totalRecords);

        }

        public override ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            MySqlParameter[] parameterArray1 = new MySqlParameter[] { this.CreateInputParam("?UserNameToMatch", MySqlDbType.VarChar, usernameToMatch), this.CreateInputParam("@InactiveSinceDate", MySqlDbType.Datetime, userInactiveSinceDate.ToUniversalTime()) };
            return this.GetProfilesForQuery(parameterArray1, authenticationOption, pageIndex, pageSize, out totalRecords);

        }

        private ProfileInfoCollection GetProfilesForQuery(MySqlParameter[] args, ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords)
        {
           if (pageIndex < 0)
                throw new ArgumentException("Page index must be non-negative", "pageIndex");
            if (pageSize < 1)
                throw new ArgumentException("Page size must be positive", "pageSize");

            long lBound = (long)pageIndex * pageSize;
            long uBound = lBound + pageSize - 1;

            if (uBound > System.Int32.MaxValue)
            {
                throw new ArgumentException("pageIndex*pageSize too large");
            }
            object obj1 = Aspnet_profileDTO.Count_TotalProfiles(args, ApplicationId, (int)authenticationOption);
            if (obj1 == null) 
            {
                totalRecords = 0;
            }
            else
                totalRecords = Convert.ToInt32(obj1);

            return Aspnet_profileDTO.GetProfiles(args, ApplicationId, (int)authenticationOption, lBound, uBound);
        }

        private bool DeleteProfile(string username, uint appId) {
            Aspnet_usersDAL user = Aspnet_usersDTO.SelectByFk_ApplicationId_UserNameWithPersistance(appId, username);
            if (user == null)
                return false;
            Aspnet_profileDAL profile = new Aspnet_profileDAL();
            profile.UserId = user.UserId;
            Aspnet_profileDTO.DeleteByFk_UserId(profile);
            return true;
        }

        #region Private Methods

        private MySqlParameter CreateInputParam(string paramName, MySqlDbType dbType, object objValue)
        {
            MySqlParameter parameter1 = new MySqlParameter(paramName, dbType);
            if (objValue == null)
            {
                objValue = string.Empty;
            }
            parameter1.Value = objValue;
            return parameter1;
        }

        private uint ApplicationId
        {
            get
            {
                return Aspnet_applicationsDTO.GetApplicationId(_AppName);
            }
        }


        #endregion

    }
}
